/********************************************************************************
* @file    uart_ble_module_c.c （主机端）
* @author  jianqiang.xue
* @version V1.0.0
* @date    2022-03-30
* @brief   协议路径：Public\Protocol
            有线通讯
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>

#include "bsp_gpio.h"
#include "bsp_uart.h"
#include "log.h"
#include "queue.h"
/* Private Includes ----------------------------------------------------------*/
#include "biz_usb.h"
#include "usbd_desc.h"
#include "app_main.h"
#include "biz_power.h"

#include "uart_nrf_ble.h"
#include "ls_gpio.h"
#include "ls_syscfg.h"
/* Private Define ------------------------------------------------------------*/
#define SUCCESS 0
#define FAILED  1

#define PROT_CMD_HEAD_PACK(BUFF, CMD, LEN)     \
do                                             \
{                                              \
    BUFF[0] = 0x55;                            \
    BUFF[1] = 0x56;                            \
    BUFF[2] = CMD;                             \
    BUFF[3] = LEN;                             \
}while(0);                                     \

#define PROT_PC_CMD_HEAD_PACK(BUFF, STRING_ID) \
do                                             \
{                                              \
    BUFF[0] = 0x80;                            \
    BUFF[1] = 0x06;                            \
    BUFF[2] = STRING_ID;                       \
    BUFF[3] = 1;                               \
}while(0);                                     \

/* External Variables --------------------------------------------------------*/
/* Private Macro -------------------------------------------------------------*/
/* Private Variables ---------------------------------------------------------*/
ble_info_t g_ble_info = {0};
bool g_ble_conn_state               = false;
bool g_bat_flag                     = false;
uint8_t g_bat_soc                   = 0;
uint8_t data_temp[32]               = {0};

bool g_ble_addr_flag                = false;
bool g_ble_ver_flag                 = false;
bool g_ble_pair_flag                = false;
// 消息队列
#define UART_RECV_Q_ITEM_CNT                             2
#define UART_RECV_Q_ITEM_SIZE                            (20)
/***************消息队列定义**************/
 // 用于uart消息队列总缓存区
static uint8_t m_uart_recv_q_buff[UART_RECV_Q_ITEM_CNT * UART_RECV_Q_ITEM_SIZE] = {0};
queue_t m_uart_recv_q =
{
    .pbuff     = m_uart_recv_q_buff,
    .front     = 0,
    .rear      = 0,
    .item_cnt  = UART_RECV_Q_ITEM_CNT,
    .item_size = UART_RECV_Q_ITEM_SIZE
};
uint8_t g_uart_recv_data[UART_RECV_Q_ITEM_SIZE]    = {0}; // 用于uart消息临时缓存区

/* Private Function Prototypes -----------------------------------------------*/
static uint8_t get_checksum(uint8_t *data, uint8_t len)
{
    uint16_t sum = 0;
    for (uint8_t i = 0; i < len; i++)
    {
        sum += data[i];
    }
    return sum & 0x00FF;
}

/**
 * @brief  [MCU->BLE] 获取设备信息 -- 响应指令
 */
static void response_get_device_info(void)
{
    PROT_CMD_HEAD_PACK(data_temp, PROT_CMD_GET_DEVICE_INFO_RES, 0x0A);
    // 厂商 ID
    data_temp[4]  = APP_USBD_VID & 0x00FF;
    data_temp[5]  = (APP_USBD_VID >> 8) & 0x00FF;
    // 产品 ID
    data_temp[6]  = APP_USBD_PID & 0x00FF;
    data_temp[7]  = (APP_USBD_PID >> 8) & 0x00FF;
    // 最大 X 坐标值
    data_temp[8]  = X_PHYSICAL_MAX & 0x00FF;
    data_temp[9]  = (X_PHYSICAL_MAX >> 8) & 0x00FF;
    // 最大 Y 坐标值
    data_temp[10] = Y_PHYSICAL_MAX & 0x00FF;
    data_temp[11] = (Y_PHYSICAL_MAX >> 8) & 0x00FF;
    // 最大压力值
    data_temp[12] = PRESSURE_MAX & 0x00FF;
    data_temp[13] = (PRESSURE_MAX >> 8) & 0x00FF;
    //CHECKSUM
    data_temp[14] = get_checksum(data_temp, 14);
    uart_send_ble_data(data_temp, 15);
}

/**
 * @brief  [MCU->BLE] 获取设备名称 -- 响应指令
 */
static void response_get_device_name(void)
{
    uint8_t temp_len = 0;
    PROT_CMD_HEAD_PACK(data_temp, PROT_CMD_GET_DEVICE_NAME_RES, strlen(PRODUCT_NAME));
    temp_len = 4;
    // 设备名称
    memcpy(data_temp + temp_len, PRODUCT_NAME, strlen(PRODUCT_NAME));
    temp_len += strlen(PRODUCT_NAME);

    // CHECKSUM
    *(data_temp + temp_len) = get_checksum(data_temp, temp_len);
    uart_send_ble_data(data_temp, temp_len + 1);
}

/**
 * @brief  [BLE->MCU] 获取蓝牙固件版本 -- 响应指令
 * @note   协议包(括号里面是字节位)：HEADER(0,1) CMD(2) LENGTH(3) BAT_LEVEL(n) CHECKSUM(n+1)
 *         BAT_LEVEL: 0~100(success)||0xff(0xff)
 */
static void response_ble_ver(uint8_t *data, uint16_t len)
{
    if (memcmp(g_ble_info.version, &data[4], data[3]) != 0)
    {
        // 版本长度过长，BLE不显示，最大长度28
        if(data[3] > 20)
        {
            data[3] = 20;
        }
        memcpy(g_ble_info.version, data + 4, data[3]);
        g_ble_info.write_in = true;
    }
    g_ble_ver_flag = true;
}

/**
 * @brief  [BLE->MCU] 获取电池电量 -- 响应指令
 * @note   协议包(括号里面是字节位)：HEADER(0,1) CMD(2) LENGTH(3) BAT_LEVEL(4) CHECKSUM(5)
 *         BAT_LEVEL: 0~100(success)||0xff(0xff)
 */
static void response_bat_soc(uint8_t *data, uint16_t len)
{
    g_bat_soc = data[4];
    g_bat_flag = true;
//    LOG_D("<DEBUG> [res_bat_soc]: ble_soc 0x%02x\r\n", data[4]);
    main_send_signal(SIGNAL_REFRESH_BAT);
}

/**
 * @brief  [BLE->MCU] 获取充电状态 -- 响应指令
 * @note   协议包(括号里面是字节位)：HEADER(0,1) CMD(2) LENGTH(3) RESULT(4) CHECKSUM(5)
 *         RESULT 0--未充电 1--充电中
 */
static void response_charge(uint8_t *data, uint16_t len)
{
    set_usb_state(data[4]);
    main_send_signal(SIGNAL_REFRESH_BAT);
}

/**
 * @brief  [BLE->MCU] 获取蓝牙地址 -- 响应指令
 * @note   协议包(括号里面是字节位)：HEADER(0,1) CMD(2) LENGTH(3) MAC(4,5,6,7,8,9) CHECKSUM(10)
 */
static void response_ble_addr(uint8_t *data, uint16_t len)
{
    //LOG_I("%02x %02x %02x %02x  %02x %02x\r\n", data[0], data[1], data[2], data[3], data[8], data[9]);
    if (memcmp(g_ble_info.mac_addr, &data[4], BLE_MAC_MAX_VAL) != 0)
    {
        g_ble_info.write_in = true;
        memcpy(g_ble_info.mac_addr, &data[4], BLE_MAC_MAX_VAL);
        LOG_I("<INFO> [res_ble_addr]: %02x %02x %02x %02x %02x %02x\r\n",
        g_ble_info.mac_addr[0], g_ble_info.mac_addr[1], g_ble_info.mac_addr[2],
        g_ble_info.mac_addr[3], g_ble_info.mac_addr[4], g_ble_info.mac_addr[5]);
    }
    g_ble_addr_flag = true;
}

/**
 * @brief  [BLE->MCU] 蓝牙进入配对模式 -- 响应指令
 * @note   协议包(括号里面是字节位)：HEADER(0,1) CMD(2) LENGTH(3) RESULT(4) CHECKSUM(5)
 *         RESULT 0--success 1--failed
 */
static void response_ble_enter_pair_mode(uint8_t *data, uint16_t len)
{
    if (data[4] == 0)
    {
        g_ble_pair_flag = true;
    }
    LOG_I("<INFO> [ble_enter_pair]: %02x\r\n", data[4]);
}

/**
 * @brief  [BLE->MCU] 蓝牙连接状态获取 -- 响应指令
 * @note   协议包(括号里面是字节位)：HEADER(0,1) CMD(2) LENGTH(3) RESULT(4) CHECKSUM(5)
 *         RESULT 0--未连接 1--已连接
 */
static void response_ble_connect_state(uint8_t *data, uint16_t len)
{
    g_ble_conn_state = (bool)data[4];
    if (g_ble_conn_state)
    {
        g_ble_pair_flag = true;
    }
    LOG_I("<INFO> [ble_conn_ste]: %02x\r\n", g_ble_conn_state);
}

/**
 * @brief  [BLE->MCU] 蓝牙配对 -- 响应指令
 * @note   协议包(括号里面是字节位)：HEADER(0,1) CMD(2) LENGTH(3) RESULT(4) CHECKSUM(5)
 *         RESULT 0--success 1--failed
 */
static void response_ble_pair(uint8_t *data, uint16_t len)
{
    if (data[4] == 0)
    {
        g_ble_pair_flag = true;
    }
    LOG_I("<INFO> [ble_pair]: %02x\r\n", data[4]);
}

/**
 * @brief  [device->MCU] 获命令透传指令 -- 设备 send to 手写板
 * @note   协议包(括号里面是字节位)：HEADER(0,1) CMD(2) LENGTH(3) PC协议包(n字节) CHECKSUM(n+1)
 * @param  device_tpye: 非dongle设备 0xF0   dongle设备 0xF2
 */
static void response_device_to_mcu(uint8_t device_tpye, uint8_t *data, uint16_t len)
{
    switch (data[4])
    {
        case 0x80:
            break;
        case 0x02:
            switch (data[5])
            {
                case 0xB0:
                    // 设置手写通道(标准笔/自定义通道)
                    LOG_D("<DEBUG> [0x%02x->MUC] [Handwriting mode switching]: 0x%02x\r\n", device_tpye, data[6]);
                    if (data[6] & 0x80)
                    {
                        set_usb_comm_channel((usb_device_data_mode_t)(data[6] - 0x80));
                    }
                    else
                    {
                        set_usb_comm_channel((usb_device_data_mode_t)data[6]);
                    }
                    response_handwrite_mode_switch(device_tpye);
                    break;
                case 0xB2:
                    // 设置系统类型
                    if (data[6] == 0x20 && data[7] == 0x10)
                    {
                        set_current_system(1);
                    }
                    else if(data[6] == 0x20 && data[7] == 0x20)
                    {
                        set_current_system(2);
                    }
                    // 设置安卓手写方向
                    else if (data[6] == 0x20 && data[7] == 0x01)
                    {
                        set_current_android_angle(data[8]);
                    }
//                    LOG_D("<DEBUG> [0x%02x->MUC] [set_current_android_angle]: 0x%02x\r\n", device_tpye, get_current_android_angle());
//                    LOG_D("<DEBUG> [0x%02x->MUC] [get_current_system]: 0x%02x\r\n", device_tpye, get_current_system());
                case 0xB4:
                    // 获取当前触控控制
                    break;
                case 0xB8:
                    // 获取当前电量信息
                    main_send_signal(SIGNAL_REFRESH_BAT);
                    LOG_D("<DEBUG> SIGNAL_REFRESH_BAT 0xB8\r\n");
                    break;
                default:
                    break;
            }
            break;
        default:
            break;
    }
    bsp_uart_reset_rxbuff(BOARD_UART_COMM);
}

/* Public Function Prototypes ------------------------------------------------*/
void* get_ble_info_p(void)
{
    return &g_ble_info;
}

bool get_ble_info_whether_write(void)
{
    return g_ble_info.write_in;
}

void set_ble_info_whether_write(bool state)
{
    g_ble_info.write_in = state;
}

uint8_t* get_ble_mac_addr(void)
{
    return g_ble_info.mac_addr;
}

bool get_bat_soc_state(void)
{
    return g_bat_flag;
}

uint8_t get_ble_soc(void)
{
    return g_bat_soc;
}

bool get_ble_conn_state(void)
{
    return g_ble_conn_state;
}

/**
 * @brief  BLE消息队列初始化
 */
void biz_ble_queue_init(void)
{
    queue_init(&m_uart_recv_q, m_uart_recv_q_buff, UART_RECV_Q_ITEM_CNT, UART_RECV_Q_ITEM_SIZE);
    memset(m_uart_recv_q_buff, 0, UART_RECV_Q_ITEM_CNT * UART_RECV_Q_ITEM_SIZE);
    memset(g_uart_recv_data, 0, UART_RECV_Q_ITEM_SIZE);
}

/**
 * @brief  发送数据给ble串口通道(消息入队，非实时发送)
 * @param  *data: 欲发送内容
 * @param  len: 内容长度(字节大小)
 */
void uart_send_ble_data(uint8_t *data, uint16_t len)
{
    if (!queue_en(&m_uart_recv_q, data, len))
    {
        LOG_D("<DEBUG> [biz_uart_send_data] queue_en fail\r\n");
    }
}

/**
 * @brief  处理消息队列中的消息，通过uart发送(放在空闲线程使用)
 */
bool uart_ble_data_dispose(void)
{
    if (bsp_uart_get_bus(BOARD_UART_COMM))
    {
        LOG_D("<DEBUG> [uart_ble_data_dispose] uart bus\r\n");
        return false;
    }
    if (!queue_de(&m_uart_recv_q, g_uart_recv_data))
        return false;
    bsp_uart_send_nbyte(BOARD_UART_COMM, g_uart_recv_data, 5 + g_uart_recv_data[3]);
    return true;
}

/**
 * @brief  将数据经过组包，再通过串口发送给ble
 * @param  cmd: 命令 参考uart_nrf_ble.h的宏定义PROT_CMD_XXXXXXX
 * @param  *data: 数据指针
 * @param  len: 数据长度
 */
void uart_prot_ble_request(uint8_t cmd, uint8_t *data, uint8_t len)
{
    if (cmd == PROT_CMD_GET_BLE_VER_REQ && g_ble_ver_flag)
    {
        return;
    }
    else if (cmd == PROT_CMD_BLE_WHITELIST_PAIRING_RES && g_ble_pair_flag)
    {
        return;
    }
    // 组合头包数据
    PROT_CMD_HEAD_PACK(data_temp, cmd, len);
    // 填充数据
    if (data != NULL)
    {
        memcpy(data_temp + 4, data, len);
    }
    //CHECKSUM
    data_temp[4 + len] = get_checksum(data_temp, 4 + len);
    uart_send_ble_data(data_temp, 5 + len);
}

/**
 * @brief  [nrf ble协议] 对串口数据进行协议检查 格式：头(2字节 0x55 0x56) 命令(1字节) 长度(n字节) 检验和(1字节)
 * @note   为biz_uart.c文件提供
 * @param  *data: 串口数据
 * @param  len: 数据长度
 */
void uart_prot_nrf_ble_dispose_data(uint8_t *data, uint16_t len)
{
    if (data[0] != 0x55)
    {
        bsp_uart_reset_rxbuff(BOARD_UART_COMM);
        return;
    }
    if (len == 2 && data[1] != 0x56)
    {
        bsp_uart_reset_rxbuff(BOARD_UART_COMM);
        return;
    }

    if (len < data[3] + 5)
    {
        return;
    }
    uint8_t checksum = 0;
    checksum = get_checksum(data, len - 1);
    if (checksum != data[len - 1])
    {
        LOG_E("<ERR> [prot_nrf_conn]: check fail %02x|%02x\r\n", checksum, data[len - 1]);
        bsp_uart_reset_rxbuff(BOARD_UART_COMM);
        return;
    }
//     LOG_D("<DEBUG> [nrf_ble]: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x||len:%d\r\n",
//             data[0], data[1], data[2], data[3], data[4],
//             data[5], data[6], data[7], data[8], data[9], len);
    switch(data[2])
    {
        case PROT_CMD_GET_DEVICE_INFO_REQ:
            response_get_device_info();
            bsp_uart_reset_rxbuff(BOARD_UART_COMM);
            LOG_D("<DEBUG> [nrf_ble]: PROT_CMD_GET_DEVICE_INFO_REQ\r\n");
            break;
        case PROT_CMD_GET_DEVICE_NAME_REQ:
            response_get_device_name();
            bsp_uart_reset_rxbuff(BOARD_UART_COMM);
            LOG_D("<DEBUG> [nrf_ble]: PROT_CMD_GET_DEVICE_NAME_REQ\r\n");
            break;
        case PROT_CMD_GET_BLE_VER_RES:
            response_ble_ver(data, len);
            bsp_uart_reset_rxbuff(BOARD_UART_COMM);
            break;
        case PROT_CMD_GET_BAT_SOC_RES:
//           LOG_D("<DEBUG> [nrf_ble]: PROT_CMD_GET_BAT_SOC_RES %02x %02x %02x %02x\r\n", data[3], data[4], data[5], data[6]);
            response_bat_soc(data, len);
            bsp_uart_reset_rxbuff(BOARD_UART_COMM);
            break;
        case PROT_CMD_GET_CHARG_RES:
            response_charge(data, len);
            bsp_uart_reset_rxbuff(BOARD_UART_COMM);
            LOG_D("<DEBUG> [nrf_ble]: PROT_CMD_GET_CHARG_RES\r\n");
            break;
        case PROT_CMD_GET_BLE_ADDR_RES:
            response_ble_addr(data, len);
            bsp_uart_reset_rxbuff(BOARD_UART_COMM);
            LOG_D("<DEBUG> [nrf_ble]: PROT_CMD_GET_BLE_ADDR_RES\r\n");
            break;
        case PROT_CMD_BLE_IN_PAIRING_RES:
            response_ble_pair(data, len);
            bsp_uart_reset_rxbuff(BOARD_UART_COMM);
            LOG_D("<DEBUG> [nrf_ble]: PROT_CMD_BLE_IN_PAIRING_RES %d\r\n", data[4]);
            break;
        case PROT_CMD_BLE_WHITELIST_PAIRING_RES:
            response_ble_enter_pair_mode(data, len);
            bsp_uart_reset_rxbuff(BOARD_UART_COMM);
            LOG_D("<DEBUG> [nrf_ble]: PROT_CMD_BLE_WHITELIST_PAIRING_RES %d\r\n", data[4]);
            break;
        case PROT_CMD_BLE_CONN_STATE_RES:
            response_ble_connect_state(data, len);
            bsp_uart_reset_rxbuff(BOARD_UART_COMM);
            LOG_D("<DEBUG> [nrf_ble]: PROT_CMD_BLE_CONN_STATE_RES %d\r\n", data[4]);
            break;
        case PROT_CMD_PC_TO_MCU:
            response_device_to_mcu(PROT_CMD_PC_TO_MCU, data, len);
            // LOG_D("<DEBUG> PROT_CMD_PC_TO_MCU \r\n");
            break;
        case PROT_CMD_MCU_TO_MP:
            response_device_to_mcu(PROT_CMD_MCU_TO_MP, data, len);
            // LOG_D("<DEBUG> PROT_CMD_PC_TO_MCU \r\n");
            break;
        default:
            break;
    }
}

void biz_ble_enter_sleep(void)
{
    bsp_gpio_set_pin(NRF_IQR_EN_PORT, NRF_IRQ_EN_PIN, BSP_GPIO_PIN_RESET);
    uart_prot_ble_request(PROT_CMD_BLE_SLEEP_REQ, NULL, 0);
}

void biz_ble_exti_sleep(void)
{
    bsp_gpio_set_pin(NRF_POWER_EN_PORT, NRF_POWER_EN_PIN, BSP_GPIO_PIN_SET);
    bsp_gpio_set_pin(NRF_IQR_EN_PORT, NRF_IRQ_EN_PIN, BSP_GPIO_PIN_SET);
    g_ble_pair_flag = false;
}

void biz_ble_init(void)
{
    // 给NRF供电(0--关闭 1--开启)
    bsp_gpio_set_clk(GPIO_APBx, BOARD_NRF_POWER_EN_GPIO_CLK, true);
    bsp_gpio_init_output(NRF_POWER_EN_PORT, NRF_POWER_EN_PIN, BSP_GPIO_PIN_OUT_PP);
    bsp_gpio_set_pin(NRF_POWER_EN_PORT, NRF_POWER_EN_PIN, BSP_GPIO_PIN_RESET);

    // NRF唤醒引脚(0--关闭 1--开启)
    bsp_gpio_set_clk(GPIO_APBx, BOARD_NRF_IQR_EN_GPIO_CLK, true);
    bsp_gpio_init_output(NRF_IQR_EN_PORT, NRF_IRQ_EN_PIN, BSP_GPIO_PIN_OUT_PP);
    bsp_gpio_set_pin(NRF_IQR_EN_PORT, NRF_IRQ_EN_PIN, BSP_GPIO_PIN_RESET);
}
